﻿using System;
using System.Diagnostics.CodeAnalysis;

namespace ChessKit.Properties
{
  /// <summary>
  /// Describes dependency between method input and output.
  /// </summary>
  /// <syntax>
  /// <p>Function Definition Table syntax:</p>
  /// <list>
  /// <item>FDT      ::= FDTRow [;FDTRow]*</item>
  /// <item>FDTRow   ::= Input =&gt; Output | Output &lt;= Input</item>
  /// <item>Input    ::= ParameterName: Value [, Input]*</item>
  /// <item>Output   ::= [ParameterName: Value]* {halt|stop|void|nothing|Value}</item>
  /// <item>Value    ::= true | false | null | notnull | canbenull</item>
  /// </list>
  /// If method has single input parameter, it's name could be omitted. <br/>
  /// Using <c>halt</c> (or <c>void</c>/<c>nothing</c>, which is the same) for method output means that the methos doesn't return normally. <br/>
  /// <c>canbenull</c> annotation is only applicable for output parameters. <br/>
  /// You can use multiple <c>[ContractAnnotation]</c> for each FDT row, or use single attribute with rows separated by semicolon. <br/>
  /// </syntax>
  /// <examples>
  /// <list>
  /// <item><code>
  /// [ContractAnnotation("=> halt")]
  /// public void TerminationMethod()
  /// </code></item>
  /// <item><code>
  /// [ContractAnnotation("halt &lt;= condition: false")]
  /// public void Assert(bool condition, string text) // Regular Assertion method
  /// </code></item>
  /// <item><code>
  /// [ContractAnnotation("s:null => true")]
  /// public bool IsNullOrEmpty(string s) // String.IsNullOrEmpty
  /// </code></item>
  /// <item><code>
  /// // A method that returns null if the parameter is null, and not null if the parameter is not null
  /// [ContractAnnotation("null => null; notnull => notnull")]
  /// public object Transform(object data) 
  /// </code></item>
  /// <item><code>
  /// [ContractAnnotation("s:null=>false; =>true,result:notnull; =>false, result:null")]
  /// public bool TryParse(string s, out Person result)
  /// </code></item>
  /// </list>
  /// </examples>
  [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
  [UsedImplicitly(ImplicitUseTargetFlags.WithMembers)] internal sealed class ContractAnnotationAttribute : Attribute
  {
    [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "fdt",
      Justification = "fdt - seems to be abbreviation of some sort of jetbrans")]
    public ContractAnnotationAttribute([NotNull] string fdt)
      : this(fdt, false)
    {
    }

    [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "fdt",
      Justification = "fdt - seems to be abbreviation of some sort of jetbrans")]
    public ContractAnnotationAttribute([NotNull] string fdt, bool forceFullStates)
    {
      FDT = fdt;
      ForceFullStates = forceFullStates;
    }

    [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "FDT",
      Justification = "fdt - seems to be abbreviation of some sort of jetbrans")]
    public string FDT { get; private set; }
    public bool ForceFullStates { get; private set; }
  }
}